package org.example.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.mysql.cj.xdevapi.JsonArray;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.example.JavaBean.plus.Emp;
import org.example.handler.EmpNotDeleteException;
import org.example.handler.EmpNotFoundException;
import org.example.handler.FaildUpdateEmpException;
import org.example.mapper.EmpMapper;
import org.example.service.EmpService;
import org.example.util.JsonResult;
import org.example.util.ResultTool;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @Auther:Liu
 * @Testname:EmpServiceImpl
 * @Date:2025/8/12 10:34
 */
@Slf4j
@Service
public class EmpServiceImpl extends ServiceImpl<EmpMapper, Emp> implements EmpService {
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public JsonResult findEmpById(Integer id) {
        ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
        String s = ops.get("emp" + id);
        if (s != null) {
            Emp emp = JSONArray.parseObject(s, Emp.class);
            return ResultTool.success(emp);
        }
        Emp emp = getById(id);
        if (emp == null) {
            throw new EmpNotFoundException("emp not found");
//            return ResultTool.fail(501, "数据库中对象数据不存在");
        }
        ops.set("emp" + id, JSONArray.toJSONString(emp));
        return ResultTool.success(emp);
    }

    @Override
    public JsonResult deleteEmpById(Integer id) {
        boolean b = removeById(id);
        if (!b) {
            throw new EmpNotFoundException("emp not found");
//            return ResultTool.fail(501, "对象信息不存在");
        }
        Boolean deleted = stringRedisTemplate.delete("emp" + id);
        return ResultTool.success(deleted);
    }

    @Override
    public JsonResult updateEmp(Emp emp) {
        boolean b = updateById(emp);
        if (!b) {
            throw new FaildUpdateEmpException("emp not update");
//            return ResultTool.fail(501, "更新数据失败");
        }
        ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();

        String s = ops.get("emp" + emp.getEmpno());
        if (s == null) {
            return ResultTool.success("success");
        }
        ops.set("emp" + emp.getEmpno(), JSONArray.toJSONString(emp));
        return ResultTool.success("success");
    }

    /**
     * 注解形式的查找数据
     *
     * @param id
     * @return
     */
    @Cacheable(cacheNames = "emp", key = "#id")
    public JsonResult findEmpById2(Integer id) {
        log.info("开始查询数据库{}信息", id);
        return ResultTool.success(getById(id));
    }

    /**
     * 注解形式的删除数据
     * // 清空所有的缓存数据
     * // @CacheEvict(allEntries = true)
     *
     * @param id
     * @return
     */
    @CacheEvict(cacheNames = "emp", key = "#id")
    public JsonResult deleteEmpById2(Integer id) {
        return ResultTool.success(removeById(id));
    }

    /**
     * 注解形式的修改数据
     */
    @CachePut(cacheNames = "emp", key = "#emp.empno")
    public JsonResult updateEmp2(Emp emp) {
        log.info("开始查询数据库信息");
        updateById(emp);
        return ResultTool.success(getById(emp.getEmpno()));
    }

    @Override
    public JsonResult findPage(int page) {
        ListOperations<String, String> ops = stringRedisTemplate.opsForList();
        log.info("开始查询第{}页数据", page);
        Long size = ops.size("List");
        log.info("当前Redis中存放了{}条数据", size);
        if (size == null || size == 0 || size <= (page - 1) * 10) {
            IPage<Emp> iPage = Page.of(page, 10);
            log.info("没有存Redis中查到数据，从数据库中取数据");
            List<Emp> list = list(iPage);
            for (Emp emp : list) {
                ops.rightPushAll("List", JSONArray.toJSONString(emp));
            }
            iPage.setRecords(list);
            return ResultTool.success(iPage);
        }
        log.info("从Redis中查到了数据,直接遍历数据");
        List<String> list = ops.range("List", (page - 1) * 10, page * 10);
        Page<Emp> page1 = Page.of(page, 10);
        ArrayList<Emp> arrayList = new ArrayList<>();
        for (String emp : list) {
            arrayList.add(JSONArray.parseObject(emp, Emp.class));
        }
        page1.setRecords(arrayList);
        return ResultTool.success(page1);
    }

    @Cacheable(cacheNames = "emp_page", key = "#page")
    public JsonResult findPage1(int page) {
        IPage<Emp> iPage = Page.of(page, 10);
        List<Emp> list = list(iPage);
        iPage.setRecords(list);
        return ResultTool.success(iPage);
    }

    /**
     * mysql与Redis数据同步
     * @param page
     * @return
     */
    public JsonResult findPage2(int page) {
        ListOperations<String, String> ops = stringRedisTemplate.opsForList();
        int start = (page - 1) * 10;
        int end = start + 9;
        // 1. 判断是否为空
        Long size = ops.size("emp");
        log.info("当前Redis的size为{}",size);
        // 1.2 为空，Redis中无数据，开始从数据库中取数据
        if (size == null || size == 0) {
            log.info("size为空，开始从数据库中取元素");
            Page<Emp> iPage = Page.of(page, 10);
            List<Emp> sqlEmpList = list(iPage);
            // 2. 利用分页获取数据总条数，填充为null
            for (int i = 0; i < iPage.getTotal(); i++) {
                ops.rightPushAll("emp", "null");
            }
            // 2.1 从数据库中获取十条数据

            int index=start;
            // 2.2 将数据存入Redis中，通过更新修改null为新数据
            for (Emp emp : sqlEmpList) {
                ops.set("emp",index,JSONArray.toJSONString(emp));
                index++;
            }
            iPage.setRecords(sqlEmpList);
            return ResultTool.success(iPage);
        }
        // 3. 如果Redis不为空，则判断该页数据是否在Redis中存在
        List<String> redislist = ops.range("emp", start, end);
        int size1 = redislist.size();

        if (redislist.get(0).equals("null")||redislist.get(size1-1).equals("null")) {
            log.info("当前Redis中无该元素，开始查数据库");
            // 3.1 Redis中不存在该数据,开始查询数据库
            Page<Emp> iPage = Page.of(page, 10);
            List<Emp> sqlList = list(iPage);

            int index=start;
            for (Emp emp : sqlList) {
                ops.set("emp", index,JSONArray.toJSONString(emp));
                index++;
            }
            iPage.setRecords(sqlList);
            return ResultTool.success(iPage);
        }
        // 3.2 Redis中存在数据，直接取出数据
        log.info("当前Redis中存在该元素，直接返回");
        ArrayList<Emp> emps = new ArrayList<Emp>();
        for (String emp : redislist) {
            emps.add(JSONArray.parseObject(emp, Emp.class));
        }
        Page<Emp> iPage = Page.of(page, 10);
        iPage.setRecords(emps);
        return ResultTool.success(iPage);
    }

    /**
     * 同步删除
     * @param id
     * @return
     */
    public JsonResult deletePage2(int id) {
        boolean b = removeById(id);
        if (!b){
            throw new EmpNotDeleteException("删除失败");
        }
        ListOperations<String, String> ops = stringRedisTemplate.opsForList();
        List<String> list = ops.range("emp", 0, -1);
        if (list!=null){
            list.forEach(item->{
                if (!"null".equals(item)) {
                    Emp emp = JSONArray.parseObject(item, Emp.class);
                    if (emp.getEmpno()==id){
                        ops.remove("emp",1,item);
                    }
                }
            });
        }
        return ResultTool.success("success");
    }

    /**
     * 同步修改
     * @param emp
     * @return
     */
    public JsonResult updatePage2(Emp emp) {
        boolean b = updateById(emp);
        if (!b) {
            throw new FaildUpdateEmpException("更新失败");
        }
        ListOperations<String, String> ops = stringRedisTemplate.opsForList();
        List<String> list = ops.range("emp", 0, -1);
        final int[] index = {0};
        if (list!=null){
            list.forEach(item->{
                if (!"null".equals(item)) {
                    Emp emp1 = JSONArray.parseObject(item, Emp.class);
                    if (Objects.equals(emp.getEmpno(), emp1.getEmpno())){
                        ops.set("emp", index[0],JSONArray.toJSONString(emp));
                    }
                }
                index[0]++;
            });
        }
        return ResultTool.success("success");
    }


}
